#include "drv_softi2c_bq769x0.h"
#include "drv_soft_i2c.h"
#include "universal_util.h"

#include "stm32f1xx.h"

/* 报警接口回调 */
static BQ769X0_AlertOpsTypedef AlertOps;

/*
温度采样模式 0:热敏电阻  1:IC温度.
针对不同类型得产品:
    小体积产品 BQ 内部 IC 温度近似等价 电池包温度.
    大体积产品 外接 NTC 探头到 电池包内部.
*/
static uint8_t TempSampleMode = 0;

// 寄存器组
static RegisterGroup Registers = {0};

/* TODO:ADC增益, 这个需要探讨一下是什么东西 */
static float Gain = 0;		
static int16_t iGain = 0;
static int8_t Adcoffset;

// 短路电流一般设置为 5C, 当前工程使用电池为 普通 18650 2000mAh 电池, 建议 1C 放电.
// 因此短路电流设置为 10A, 对检流电阻用欧姆定律得 : V = IR = 10A * 0.005 = 50mV
// 因此对于 BQ 芯片的短路检测的阈值电压就设置为   SCD_THRESH_89mV_44mV
// TODO: 这里写的不太好, 应该交予一个地方统一修改
static const uint8_t SCDThresh = SCD_THRESH_89mV_44mV;

// 充放电过流阈值设置与上方同理
static const uint8_t OCDThresh = OCD_THRESH_22mV_11mV;

// 检流电阻
static float RsnsValue= 0.005;

// BQ 芯片数据
BQ769X0_SampleDataTypedef BQ769X0_SampleData = {0};

// BQ Alert 引脚外部中断回调
static void BQ769X0_AlertyHandler(void);

/*********************************** GPIO *********************************************/

static void BQ769X0_TS1_SetOutMode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
		TS1_CLK_ENABLE();  
    GPIO_InitStruct.Pin = BQ769X0_TS1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	
    HAL_GPIO_Init(BQ769X0_TS1_GPIOx, &GPIO_InitStruct);

		// 设置为输出模式后, 先拉低
		HAL_GPIO_WritePin(BQ769X0_TS1_GPIOx, BQ769X0_TS1_Pin, GPIO_PIN_RESET);
}

static void BQ769X0_TS1_SetInMode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
	
    GPIO_InitStruct.Pin = BQ769X0_TS1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(BQ769X0_TS1_GPIOx, &GPIO_InitStruct);
}

/**
  * @brief The callback mechanism of the HAL library ultimately executes this function.
	*
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == BQ769X0_ALERT_Pin)
    {
			BQ769X0_AlertyHandler();
    }
}

/**************************************************************************************/

/************************************** utils **********************************************/

/**
  * @brief  Calculates the temperature change based on the resistance of a thermistor.
  * @param  Rt: The resistance of the thermistor in ohms.
  * @retval The temperature change in Celsius.
  */
static float TempChange(float	Rt)
{
	float temp = 0;

	// The nominal resistance of the thermistor at standard temperature T2 is 10K, which I purchased.
	float Rp = 10000;

	// At Kelvin temperature, room temperature is 25 degrees Celsius.
	float T2 = 273.15 + 25;

	// B值:3935、3950
	float Bx = 3950;

	// 开尔文温度值
	float Ka = 273.15;

	// By consulting the thermistor's temperature-resistance comparison table, the following formula can be obtained.
	//sprintf((char *)buffer, "%f", Rt);
	//BQ769X0_INFO("Rts value:%s", buffer);
	temp = 1 / (1 / T2 + log(Rt / Rp) / Bx)- Ka + 0.5;

	return temp;
}


// CRC8校验
static uint8_t CRC8(uint8_t *ptr, uint8_t len, uint8_t key)
{
	uint8_t i, crc=0;
	
	while (len-- != 0)
	{
		for (i = 0x80; i != 0; i /= 2)
		{
			if ((crc & 0x80) != 0)
			{
				crc *= 2;
				crc ^= key;
			}
			else
			{
				crc *= 2;
			}

			if ((*ptr & i) != 0)
			{
				crc ^= key;
			}
		}
		ptr++;
	}
	return(crc);
}

/******************************************************************************************/


/************************************ write and read **************************************/

static bool BQ769X0_WriteRegisterByte(uint8_t Register, uint8_t data)
{
	// 地址 + 数据
	uint8_t dataBuffer[2] = {Register, data};

	struct I2C_MessageTypeDef msg = {0};

	msg.addr = BQ769X0_I2C_ADDR;
	msg.flags = I2C_WR;	
	msg.buf = dataBuffer;
	msg.tLen = 2;
	
    if (I2C_TransferMessages(&i2c1, &msg, 1) != 1)
    {
			LOG_E("Write Register Byte Fail");
			return false;
    }
    return true;
}

static bool BQ769X0_WriteRegisterByteWithCRC(uint8_t Register, uint8_t data)
{
    uint8_t dataBuffer[4];
	struct I2C_MessageTypeDef msg = {0};

	dataBuffer[0] = BQ769X0_I2C_ADDR << 1;
	dataBuffer[1] = Register;
	dataBuffer[2] = data;	
	dataBuffer[3] = CRC8(dataBuffer, 3, CRC_KEY);

	msg.addr = BQ769X0_I2C_ADDR;
	msg.flags = I2C_WR;	
	msg.buf = dataBuffer + 1;
	msg.tLen = 3;

    if (I2C_TransferMessages(&i2c1, &msg, 1) != 1)
    {
		LOG_E("Write Register Byte With CRC Fail");

		return false;
    }

    return true;
}


static bool BQ769X0_WriteRegisterWordWithCRC(uint8_t Register, uint16_t data)
{
	uint8_t dataBuffer[6];
	struct I2C_MessageTypeDef msg = {0};
	// 格式: 地址, 寄存器地址, data1, CRC(3), data2,CRC(4) 
	dataBuffer[0] = BQ769X0_I2C_ADDR << 1;
	dataBuffer[1] = Register;
	dataBuffer[2] = LOW_BYTE(data);	
	dataBuffer[3] = CRC8(dataBuffer, 3, CRC_KEY);
	dataBuffer[4] = HIGH_BYTE(data);	
	dataBuffer[5] = CRC8(dataBuffer + 4, 1, CRC_KEY);		

	msg.addr = BQ769X0_I2C_ADDR;
	msg.flags = I2C_WR;	
	// msg.buf 从寄存器地址开始
	msg.buf = dataBuffer + 1;
	msg.tLen = 5;

    if (I2C_TransferMessages(&i2c1, &msg, 1) != 1)
    {
		LOG_E("Write Register Word With CRC Fail");
		return false;
    }

    return true;
}

static bool BQ769X0_WriteBlockWithCRC(uint8_t startAddress, uint8_t *buffer, uint8_t length)
{
	uint8_t index;
	uint8_t bufferCRC[32] = {0}, *pointer;
	struct I2C_MessageTypeDef msg = {0};

	pointer = bufferCRC;
	*pointer++ = BQ769X0_I2C_ADDR << 1;
	*pointer++ = startAddress;
	*pointer++ = *buffer;
	*pointer = CRC8(bufferCRC, 3, CRC_KEY);

	// 每字节数据都需要一个 crc
	for(index = 1; index < length; index++)
	{
        pointer++;
        buffer++;
        *pointer = *buffer;
		*(pointer + 1) = CRC8(pointer, 1, CRC_KEY);
		pointer++;
	}

	msg.addr = BQ769X0_I2C_ADDR;
	msg.flags = I2C_WR;	
	msg.buf = bufferCRC + 1;
	msg.tLen = 2 * length + 1;

    if (I2C_TransferMessages(&i2c1, &msg, 1) != 1)
    {
		LOG_E("Write Register Block With CRC Fail");
		return false;
    }

    return true;	
}



static bool BQ769X0_ReadRegisterByte(uint8_t Register, uint8_t *data)
{  	
	struct I2C_MessageTypeDef msg[2] = {0};

	// msg 1 以写的方式将寄存器地址发送给 BQ 芯片
	msg[0].addr = BQ769X0_I2C_ADDR;
	msg[0].flags = I2C_WR;	
	msg[0].buf = &Register;
	msg[0].tLen = 1;

	// 切换到读取模式
	msg[1].addr = BQ769X0_I2C_ADDR;
	msg[1].flags = I2C_RD;	
	msg[1].buf = data;
	msg[1].tLen = 1;

	if (I2C_TransferMessages(&i2c1, msg, 2) != 2)
	{
	LOG_E("Read Register Byte Fail");
	return false;
	}

	return true;
}


static bool BQ769X0_ReadRegisterByteWithCRC(uint8_t Register, uint8_t *data)
{  	
	uint8_t readBuffer[2], crcInput[2], crcValue;
	struct I2C_MessageTypeDef msg[2] = {0};

	msg[0].addr = BQ769X0_I2C_ADDR;
	msg[0].flags = I2C_WR;	
	msg[0].buf = &Register;
	msg[0].tLen = 1;

	msg[1].addr = BQ769X0_I2C_ADDR;
	msg[1].flags = I2C_RD;	
	msg[1].buf = readBuffer;

	// 读取 数据 + crc 总共两个字节
	msg[1].tLen = 2;

    if (I2C_TransferMessages(&i2c1, msg, 2) != 2)
    {
		LOG_E("Read Register Byte With CRC Fail");

		return false;
    }


	crcInput[0] = (BQ769X0_I2C_ADDR << 1) + 1;
	crcInput[1] = readBuffer[0];

	crcValue = CRC8(crcInput, 2, CRC_KEY);
	if (crcValue != readBuffer[1])
	{
		LOG_E("Read Register Byte CRC Check Fail");
		return false;
    }

	*data = readBuffer[0];

	return true;
}


static bool BQ769X0_ReadRegisterWordWithCRC(uint8_t Register, uint16_t *data)
{  	
	uint8_t readBuffer[4], crcInput[2], crcValue;
	struct I2C_MessageTypeDef msg[2] = {0};

	msg[0].addr = BQ769X0_I2C_ADDR;
	msg[0].flags = I2C_WR;	
	msg[0].buf = &Register;
	msg[0].tLen = 1;

	msg[1].addr = BQ769X0_I2C_ADDR;
	msg[1].flags = I2C_RD;	
	msg[1].buf = readBuffer;

	// read buffer 中数据格式 data1, crc1, data2, crc2
	msg[1].tLen = 4;

	if (I2C_TransferMessages(&i2c1, msg, 2) != 2)
	{
		LOG_E("Read Register Word With CRC Fail");

		return false;
	}

	// crc1 是 BQ_ADDRESS 读 + data1 共同计算出来的
	crcInput[0] = (BQ769X0_I2C_ADDR << 1) + 1;
	crcInput[1] = readBuffer[0];

	crcValue = CRC8(crcInput, 2, CRC_KEY);
	if (crcValue != readBuffer[1])
	{
		LOG_E("Read Register Word CRC 1 Check Fail");

		return false;
	}

	// crc2 是 data2 计算出来的
	crcValue = CRC8(readBuffer + 2, 1, CRC_KEY);
	if (crcValue != readBuffer[3])
	{
		BQ769X0_ERROR("Read Register Word CRC 2 Check Fail");

		return false;
	}
	*data = (readBuffer[2] << 8) | readBuffer[0];

	return true;
}


static bool BQ769X0_ReadBlockWithCRC(uint8_t Register, uint8_t *buffer, uint8_t length)
{  	
	uint8_t index, crcValue, crcInput[2];
	uint8_t buf[32] = {0};
	uint8_t *readData = buf;
	struct I2C_MessageTypeDef msg[2] = {0};


	msg[0].addr = BQ769X0_I2C_ADDR;
	msg[0].flags = I2C_WR;	
	msg[0].buf = &Register;
	msg[0].tLen = 1;

	msg[1].addr = BQ769X0_I2C_ADDR;
	msg[1].flags = I2C_RD;	
	msg[1].buf = readData;
    // data1,crc1,data2,crc2,.......
	msg[1].tLen = length * 2;

    if (I2C_TransferMessages(&i2c1, msg, 2) != 2)
    {
		LOG_E("Read Register Block With CRC Cail");
		
		return false;
    }

  // crc 校验, 第一个 crc 特殊点
	crcInput[0] = (BQ769X0_I2C_ADDR << 1) + 1;
	crcInput[1] = readData[0];

	crcValue = CRC8(crcInput, 2, CRC_KEY);
	readData++;
	if (crcValue != *readData)
	{
		LOG_E("Read Register Block CRC 1 Check Fail");
		
		return false;	
	}
	else
	{
		*buffer = *(readData - 1);
	}

	for(index = 1; index < length; index++)
	{
		readData++;
		crcValue = CRC8(readData, 1, CRC_KEY);
		readData++;
		buffer++;

		if (crcValue != *readData)
		{
			LOG_E("Read Register Block CRC Check Fail");
			
			return false;		
		}
		else
		{
			*buffer = *(readData - 1);
		}
	}

	return true;
}

/******************************************************************************************/


/**************************************** 传感数据采集 *************************************/
void BQ769X0_IsMosOpen(bool *chMos, bool *disMos)
{
	*chMos = false;
	*disMos = false;
	if ( BQ769X0_ReadRegisterByte(SYS_CTRL2, &Registers.SysCtrl2.SysCtrl2Byte) )
	{
		*chMos  = Registers.SysCtrl2.SysCtrl2Bit.CHG_ON == 1;
		*disMos = Registers.SysCtrl2.SysCtrl2Bit.DSG_ON == 1;
	}
}


/* 更新单节电芯电压 */
void BQ769X0_UpdateCellVolt(void)
{
	uint8_t index = 0;
	uint16_t iTemp = 0;
	uint8_t *pRawADCData = NULL;	
	uint32_t lTemp = 0;

 	if (BQ769X0_ReadBlockWithCRC(VC1_HI_BYTE, &(Registers.VCell1.VCell1Byte.VC1_HI), BQ769X0_CELL_MAX << 1) != true)
 	{
		LOG_E("Update Cell Voltage Fail");
 	}
	
	pRawADCData = &Registers.VCell1.VCell1Byte.VC1_HI;
	for (index = 0; index < BQ769X0_CELL_MAX; index++)
	{
		iTemp = (unsigned int)(*pRawADCData << 8) + *(pRawADCData + 1);
		lTemp = ((unsigned long)iTemp * iGain) / 1000;
		lTemp += Adcoffset;
		BQ769X0_SampleData.CellVoltage[index] = lTemp / 1000.0;
		pRawADCData += 2;
	}
}

/* 更新电池组电压 */
void BQ769X0_UpdateBatVoltage(void)
{
	uint16_t adc_value = 0;
	
	if(BQ769X0_ReadRegisterWordWithCRC(BAT_HI_BYTE, &Registers.VBat.VBatWord) != true)
	{
		printf("Update Battery Voltage Fail\r\n");
	}
	
	adc_value = Registers.VBat.VBatByte.BAT_HI;
	adc_value = adc_value << 8 | Registers.VBat.VBatByte.BAT_LO;
	
	BQ769X0_SampleData.BatteryVoltage = 4 * Gain * adc_value;
	BQ769X0_SampleData.BatteryVoltage += BQ769X0_CELL_MAX * Adcoffset; //unit is mV;
	BQ769X0_SampleData.BatteryVoltage /= 1000;	
}

void BQ769X0_UpdateTsTemp(void)
{
	uint8_t index = 0;
	uint16_t iTemp = 0;
	float v_tsx = 0.0f;
	float Rts = 0.0f;
	uint8_t *pRawADCData = NULL;
	
	// Mandatory use of NTC temperature
	if(TempSampleMode != 0)
	{
		TempSampleMode = 0;
		if (BQ769X0_WriteRegisterByteWithCRC(SYS_CTRL1, 0x18) != true)
		{
			LOG_E("Update Tsx Temperature Fail");
		}
		BQ769X0_DELAY(2000);
	}
	
	// Reading the value after ADC conversion
	if (BQ769X0_ReadBlockWithCRC(TS1_HI_BYTE, &(Registers.TS1.TS1Byte.TS1_HI), BQ769X0_TMEP_MAX << 1) != true)
 	{
		LOG_E("Update Tsx Temperature Fail");
 	}
	
	for(index = 0; index < BQ769X0_TMEP_MAX; index++, pRawADCData+=2)
	{
		iTemp = (uint16_t)(*pRawADCData);
		iTemp = (iTemp << 8) | *(pRawADCData + 1);
		
		// Convert to actual voltage, where 1 bit corresponds to 382 µV, 
		v_tsx = iTemp * 0.000382;

		// Calculate the resistance of the thermistor based on the ADC value, unit: Ω
		// rts / 10K = v_tsx / (3.3V - v_tsx)
		Rts = (10000 * v_tsx) / (3.3 - v_tsx);		

		// Calculate the corresponding temperature value based on the resistance.
		BQ769X0_SampleData.TsxTemperature[index] = TempChange(Rts);
	}
	
}

/* 更新电流值 */
void BQ769X0_UpdateCurrent(void)
{
	int32_t temp = 0;
	
	// 读取检流电阻上的 ADC 值, 没增加一位电压对应 增加 8.44 uV
	if(BQ769X0_ReadRegisterWordWithCRC(CC_HI_BYTE, &Registers.CC.CCWord) != true)
	{
		LOG_E("Update current Fail\r\n");
	}
	
	temp = Registers.CC.CCByte.CC_HI;
	temp = ( temp << 8 ) |  Registers.CC.CCByte.CC_LO;
	
	// 电压转换为正值
	if(temp & 0x8000)
	{
		temp = -((~temp + 1) & 0xFFFF);
	}
	
	// 计算电流, 单位为 A
	BQ769X0_SampleData.BatteryCurrent = ((temp * 8.44) / RsnsValue) * 0.000001;
}

/******************************************************************************************/

// 报警处理
static void BQ769X0_AlertyHandler(void)
{
	uint8_t reg_value, write_value;
	
	// Read BQ state
	BQ769X0_ReadRegisterByteWithCRC(SYS_STAT, &reg_value);
	
	if( reg_value & SYS_STAT_OCD_BIT)
	{
		write_value |= SYS_STAT_OCD_BIT;
		if(AlertOps.ocd != NULL) AlertOps.ocd();
	}
	
	if( reg_value & SYS_STAT_SCD_BIT )
	{
		write_value |= SYS_STAT_SCD_BIT;
		if (AlertOps.scd != NULL) AlertOps.scd();
	}
	
	if( reg_value & SYS_STAT_OV_BIT )
	{
		write_value |= SYS_STAT_OV_BIT;
		if (AlertOps.ov != NULL) AlertOps.ov();
	}	
	
	if( reg_value & SYS_STAT_UV_BIT )
	{
		write_value |= SYS_STAT_UV_BIT;
		if (AlertOps.uv != NULL) AlertOps.uv();
	}
	
	// Alarm triggered by external circuit forcibly.
	if( reg_value & SYS_STAT_OVRD_BIT )
	{
		write_value |= SYS_STAT_OVRD_BIT;
		if( AlertOps.uv != NULL ) AlertOps.ovrd();
	}
	
	// Equipment malfunction alarm.
	if( reg_value & SYS_STAT_DEVICE_BIT )
	{
		write_value |= SYS_STAT_DEVICE_BIT;
		if( AlertOps.device != NULL ) AlertOps.device();
	}
	
	// Coulomb meter sampling completed.
	if( reg_value & SYS_STAT_CC_BIT )
	{
		write_value |= SYS_STAT_CC_BIT;
		if( AlertOps.cc != NULL ) AlertOps.cc();
	}
	
	BQ769X0_WriteRegisterByteWithCRC(SYS_STAT, write_value);
}

// 进入低功率模式
void BQ769X0_EntryShip(void)
{
	BQ769X0_WriteRegisterByteWithCRC(SYS_CTRL1, 0x00);
	BQ769X0_WriteRegisterByteWithCRC(SYS_CTRL1, 0x01);
	BQ769X0_WriteRegisterByteWithCRC(SYS_CTRL1, 0x02);
}

// 唤醒BQ芯片
void BQ769X0_Wakeup(void)
{
	// TS1 引脚设置为输出模式, 用于 weakup BQ 芯片
	BQ769X0_TS1_SetOutMode();
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
	// BQ769X0_DELAY(1000);
	
	uint32_t t = 10000;
	while(t--);
	
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
    
	// TS1 引脚设置为输入模式, 避免 BQ 芯片采集温度
	BQ769X0_TS1_SetInMode();  
	BQ769X0_DELAY(1000);
}

// \xE8\x8E峰\x8F\x96澧\x9E\xE7\x9B\x8A\xE5\x92\x8C\xE5\x81\x8F绉婚\x87\x8F
void BQ769X0_GetADCGainOffset(void)
{
	BQ769X0_ReadRegisterByteWithCRC(ADCGAIN1, &(Registers.ADCGain1.ADCGain1Byte));
	BQ769X0_ReadRegisterByteWithCRC(ADCGAIN2, &(Registers.ADCGain2.ADCGain2Byte));
	BQ769X0_ReadRegisterByteWithCRC(ADCOFFSET, &(Registers.ADCOffset));

	/*GAIN is uV/LSB,OFFSET is mV*/
	Gain = (ADCGAIN_BASE + ((Registers.ADCGain1.ADCGain1Byte & 0x0C) << 1) + ((Registers.ADCGain2.ADCGain2Byte & 0xE0)>> 5)) / 1000.0;
	iGain = ADCGAIN_BASE + ((Registers.ADCGain1.ADCGain1Byte & 0x0C) << 1) + ((Registers.ADCGain2.ADCGain2Byte & 0xE0)>> 5);

	if (Registers.ADCOffset & 0x80)
	{
		Adcoffset = 256 - (int16_t)Registers.ADCOffset * -1;
	}
	else
	{
		Adcoffset = Registers.ADCOffset;
	}
	
	//BQ769X0_INFO("Adcoffset = %d, Registers.ADCOffset = %d", Adcoffset, Registers.ADCOffset);
}

// 配置寄存器
static void BQ769X0_Configuration(void)
{
	unsigned char ReadBuffer[8];

	// 开ADC,选择外部NTC
	Registers.SysCtrl1.SysCtrl1Byte = 0x18;
	
	// 使能电流连续采样，关闭充放电MOS
	Registers.SysCtrl2.SysCtrl2Byte = 0x40;

	// 配置CC_CFG,说明书要求在初始化时应配置为0X19以获得更好的性能
	Registers.CCCfg = 0x19;

	// 写入配置到寄存器
	BQ769X0_WriteBlockWithCRC(SYS_CTRL1, &(Registers.SysCtrl1.SysCtrl1Byte), 8);
	BQ769X0_ReadBlockWithCRC(SYS_CTRL1, ReadBuffer, 8);
	
	
	//	BQ769X0_INFO("Read Compare SysCtrl1Byte 0x%02x 0x%02x", ReadBuffer[0]&0X7F, Registers.SysCtrl1.SysCtrl1Byte);
	//	BQ769X0_INFO("Read Compare SysCtrl2Byte 0x%02x 0x%02x", ReadBuffer[1], Registers.SysCtrl2.SysCtrl2Byte);
	//	BQ769X0_INFO("Read Compare Protect1Byte 0x%02x 0x%02x", ReadBuffer[2], Registers.Protect1.Protect1Byte);
	//	BQ769X0_INFO("Read Compare Protect2Byte 0x%02x 0x%02x", ReadBuffer[3], Registers.Protect2.Protect2Byte);
	//	BQ769X0_INFO("Read Compare Protect3Byte 0x%02x 0x%02x", ReadBuffer[4], Registers.Protect3.Protect3Byte);
	//	BQ769X0_INFO("Read Compare OVTrip 0x%02x 0x%02x", ReadBuffer[5], Registers.OVTrip);
	//	BQ769X0_INFO("Read Compare UVTrip 0x%02x 0x%02x", ReadBuffer[6], Registers.UVTrip);
	//	BQ769X0_INFO("Read Compare CCCfg 0x%02x 0x%02x", ReadBuffer[7], Registers.CCCfg);
	
	
	// 去掉BUFF[0]的最高位,防止因为接上了负载使负载检测置位而没通过校验
	if( (ReadBuffer[0]&0X7F) != Registers.SysCtrl1.SysCtrl1Byte
		|| ReadBuffer[1] != Registers.SysCtrl2.SysCtrl2Byte
		|| ReadBuffer[2] != Registers.Protect1.Protect1Byte
		|| ReadBuffer[3] != Registers.Protect2.Protect2Byte
		|| ReadBuffer[4] != Registers.Protect3.Protect3Byte
		|| ReadBuffer[5] != Registers.OVTrip
		|| ReadBuffer[6] != Registers.UVTrip
		|| ReadBuffer[7] != Registers.CCCfg)
	{
		LOG_E("BQ769X0 config register fail,Please reset BMS board");
		while(1);
	}
}

// Control charge and discharge switch
void BQ769X0_ControlDSGOrCHG(BQ769X0_ControlTypedef ControlType, BQ769X0_StateTypedef NewState)
{
	if (NewState == BQ_STATE_ENABLE)
	{
		Registers.SysCtrl2.SysCtrl2Byte |= ControlType;
	}
	else
	{
		Registers.SysCtrl2.SysCtrl2Byte &= ~ControlType;
	}
	BQ769X0_WriteRegisterByteWithCRC(SYS_CTRL2, Registers.SysCtrl2.SysCtrl2Byte);
}

void BQ76X0_GpioInit()
{
#if 0
    GPIO_InitTypeDef gpio_initstruct;
    TS1_CLK_ENABLE();                                     

    gpio_initstruct.Pin = BQ769X0_TS1_Pin;                        
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;            
    gpio_initstruct.Pull = GPIO_PULLUP;                    
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;          
    HAL_GPIO_Init(BQ769X0_TS1_GPIOx, &gpio_initstruct);
#endif
	
  GPIO_InitTypeDef GPIO_InitStruct = {0};
	// Alert pin config : 
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	// Configure priority and enable interrupts.
	HAL_NVIC_SetPriority(EXTI15_10_IRQn, 1, 1);
	HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

// BQ芯片初始化
void BQ769X0_Initialize(BQ769X0_InitDataTypedef *InitData)
{
	BQ76X0_GpioInit();

#if 0
	
	// 进入睡眠再唤醒相当于复位一次BQ芯片
	BQ769X0_EntryShip();
	//BQ769X0_DELAY(500); //bug \xE5\x9Cㄩ\x9D\x9E浠诲\x8A′腑浣跨\x94ㄥ欢\xE6\x97\xB6, 浼\x9A\xE5\x8F\x91\xE7\x94\x9F hartfault 
	
	uint32_t t = 5000;
	while(t--);
	BQ769X0_Wakeup();

#endif
	
	// 获取增益和偏移量
	BQ769X0_GetADCGainOffset();


	AlertOps = InitData->AlertOps;

	// 配置寄存器
	Registers.Protect1.Protect1Bit.SCD_THRESH = SCDThresh;
	Registers.Protect2.Protect2Bit.OCD_THRESH = OCDThresh;
	Registers.Protect1.Protect1Bit.SCD_DELAY  = InitData->ConfigData.SCDDelay;	
	Registers.Protect2.Protect2Bit.OCD_DELAY  = InitData->ConfigData.OCDDelay;	
	Registers.Protect3.Protect3Bit.UV_DELAY   = InitData->ConfigData.UVDelay;	
	Registers.Protect3.Protect3Bit.OV_DELAY   = InitData->ConfigData.OVDelay;
	Registers.OVTrip = (uint8_t)((((uint16_t)((InitData->ConfigData.OVPThreshold - Adcoffset)/Gain/* + 0.5*/) - OV_THRESH_BASE) >> 4) & 0xFF);
	Registers.UVTrip = (uint8_t)((((uint16_t)((InitData->ConfigData.UVPThreshold - Adcoffset)/Gain/* + 0.5*/) - UV_THRESH_BASE) >> 4) & 0xFF);
	
	BQ769X0_Configuration();

//	BQ769X0_INFO("OVTrip:%d", Registers.OVTrip);
//	BQ769X0_INFO("UVTrip:%d", Registers.UVTrip);
	
	LOG_I("BQ769X0 Initialize successful!");
}

